package com.louis.hookproject;

import android.app.Application;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.ArrayMap;
import android.util.Log;

import com.louis.hookproject.hook.ActivityTaskHook;
import com.louis.hookproject.hook.HookH;
import com.louis.hookproject.hookutil.Reflection;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class HookApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Reflection.unseal(this);

        //开始hook
        ActivityTaskHook taskHook = new ActivityTaskHook(this);
        taskHook.hookService();
        HookH.hook_mH(this);

//        try {
//            hookAmsAction();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//
//        try {
//            hookLaunchActivity();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }


    /**
     * 在执行AMS之前，替换可用的Activity
     */
    private void hookAmsAction() throws Exception {

        //动态代理
        Class<?> mIActivityManagerClass = Class.forName("android.app.IActivityManager");

        //拿到ActivityManager对象，让动态代理里面的invoke正常执行下去

        Class<?> mActivityManagerClass = Class.forName("android.app.ActivityManager");
        Method getServiceMethod = mActivityManagerClass.getMethod("getService");
        getServiceMethod.setAccessible(true);
        final Object mIActivityManagerObj = getServiceMethod.invoke(null);

        Object mIActivityManagerProxy = Proxy.newProxyInstance(HookApplication.class.getClassLoader(),
                new Class[]{mIActivityManagerClass},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Log.d("hook", "拦截到IActivityManager里面的方法 " + method.getName());

                        if ("startActivity".equals(method.getName())) {
                            //自己的业务逻辑
                            //换成可以通过AMS检查的Activity
                            Intent intent = new Intent(HookApplication.this, ProxyActivity.class);
                            intent.putExtra("actionIntent", ((Intent) args[2]));
                            args[2] = intent;
                        }
                        //让系统继续执行
                        return method.invoke(mIActivityManagerObj, args);
                    }
                });

        //拿IActivityManagerSingleton
        //通过ActivityManager拿到IActivityManagerSingleton
        Field IActivityManagerSingletonField = mActivityManagerClass.getDeclaredField("IActivityManagerSingleton");
        IActivityManagerSingletonField.setAccessible(true);
        Object IActivityManagerSingletonObj = IActivityManagerSingletonField.get(null);

        //替换点
        Class<?> mSingletonClass = Class.forName("android.util.Singleton");
        //获取此字段mInstance
        Field mInstanceField = mSingletonClass.getDeclaredField("mInstance");
        mInstanceField.setAccessible(true);
        //替换
        mInstanceField.set(IActivityManagerSingletonObj, mIActivityManagerProxy);
    }


    /**
     * Hook LaunchActivity
     *
     * @throws Exception
     */
    private void hookLaunchActivity() throws Exception {
        Field mCallbackField = Handler.class.getDeclaredField("mCallback");
        mCallbackField.setAccessible(true);

        Class<?> mActivityThreadClass = Class.forName("android.app.ActivityThread");

        Object currentActivityThreadObj = mActivityThreadClass.getMethod("currentActivityThread").invoke(null);

        Field mHField = mActivityThreadClass.getDeclaredField("mH");
        mHField.setAccessible(true);
        Handler handler = (Handler) mHField.get(currentActivityThreadObj);

        mCallbackField.set(handler, new MyCallback(handler,currentActivityThreadObj));
    }


    class MyCallback implements android.os.Handler.Callback {

        private Handler mH;
        private Object mActivityThread;

        public MyCallback(Handler handler,Object activityThread) {
            this.mH = handler;
            this.mActivityThread = activityThread;
        }

        @Override
        public boolean handleMessage(Message msg) {
            Log.d("MyCallback", "handleMessage: " + msg.what);
            if (msg.what == 160) {
                try {
                    Class<?> mActivityThreadClass = Class.forName("android.app.ActivityThread");
                    ArrayMap mActivities = (ArrayMap) mActivityThreadClass.getField("mActivities").get(mActivityThread);
                    Object activityClientRecord = mActivities.get(msg.obj);
                    Field intentField = activityClientRecord.getClass().getDeclaredField("intent");
                    intentField.setAccessible(true);

                    Intent intent = (Intent) intentField.get(activityClientRecord);
                    Intent actionIntent = intent.getParcelableExtra("actionIntent");
                    if (actionIntent != null) {
                        intentField.set(activityClientRecord, actionIntent);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            mH.handleMessage(msg);


            return true;
        }
    }
}

